(*
 * Copyright 2014, General Dynamics C4 Systems
 *
 * This software may be distributed and modified according to the terms of
 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
 * See "LICENSE_GPLv2.txt" for details.
 *
 * @TAG(GD_GPL)
 *)

(*
Top level architecture related proofs.
*)

theory Arch_AI
imports Untyped_AI Finalise_AI
begin

definition
  "valid_aci aci \<equiv> case aci of ArchInvocation_A.MakePool frame slot parent base \<Rightarrow>   
  \<lambda>s. cte_wp_at (\<lambda>c. c = cap.NullCap) slot s \<and> real_cte_at slot s \<and>
  ex_cte_cap_wp_to is_cnode_cap slot s \<and>  
  slot \<noteq> parent \<and>  
  cte_wp_at (\<lambda>cap. \<exists>idx. cap = cap.UntypedCap frame pageBits idx ) parent s \<and>  
  descendants_of parent (cdt s) = {} \<and>
  is_aligned base asid_low_bits \<and> base \<le> 2^asid_bits - 1 \<and>
  arm_asid_table (arch_state s) (asid_high_bits_of base) = None"


lemma safe_parent_strg:
  "cte_wp_at (\<lambda>cap. cap = cap.UntypedCap frame pageBits idx) p s \<and> 
   descendants_of p (cdt s) = {} \<and> 
   valid_objs s
  \<longrightarrow>
  cte_wp_at (safe_parent_for (cdt s) p
             (cap.ArchObjectCap (arch_cap.ASIDPoolCap frame base)))
             p s"
  apply (clarsimp simp: cte_wp_at_caps_of_state safe_parent_for_def is_physical_def arch_is_physical_def)
  apply (rule is_aligned_no_overflow)
  apply (drule (1) caps_of_state_valid_cap)
  apply (clarsimp simp: valid_cap_def cap_aligned_def)
  done


lemma asid_low_bits_pageBits:
  "Suc (Suc asid_low_bits) = pageBits"
  by (simp add: pageBits_def asid_low_bits_def)

(* 32-bit instance of Detype_AI.range_cover_full *)
lemma range_cover_full:
  "\<lbrakk>is_aligned ptr sz;sz<word_bits\<rbrakk> \<Longrightarrow> range_cover (ptr::word32) sz sz (Suc 0)"
   by (clarsimp simp:range_cover_def unat_eq_0 le_mask_iff[symmetric] word_and_le1 word_bits_def)


lemma arch_state_detype[simp]:
  "arch_state (detype S s) = arch_state s"
  by (simp add: detype_def)


lemma invs_strgs:
  "invs s \<longrightarrow> valid_pspace s"
  "invs s \<longrightarrow> valid_mdb s"
  "invs s \<longrightarrow> valid_objs s"
  "invs s \<longrightarrow> pspace_aligned s"
  by auto

definition
  valid_arch_inv :: "ArchInvocation_A.arch_invocation \<Rightarrow> 'z::state_ext state \<Rightarrow> bool"
where
  "valid_arch_inv ai \<equiv> case ai of
     arch_invocation.InvokePageTable pti \<Rightarrow> 
       valid_pti pti
   | arch_invocation.InvokePageDirectory pdi \<Rightarrow>
       valid_pdi pdi
   | arch_invocation.InvokePage pi \<Rightarrow>
       valid_page_inv pi
   | arch_invocation.InvokeASIDControl aci \<Rightarrow>
       valid_aci aci
   | arch_invocation.InvokeASIDPool ap \<Rightarrow>
       valid_apinv ap"


lemma assocs_dom_comp:
  "set (map fst (filter (\<lambda>(x,y). P x \<and> y = None) (assocs f))) = (- dom f \<inter> Collect P)"
  apply (clarsimp simp: in_assocs_is_fun)
  apply (rule set_eqI)
  apply clarsimp
  apply (rule iffI, clarsimp)
  apply (erule conjE)
  apply (drule not_in_domD)
  apply (rule_tac x="(x,None)" in image_eqI)
   apply simp
  apply simp
  done


lemma assocs_empty_dom_comp:
  "(- dom f \<inter> Collect P = {}) = null (filter (\<lambda>(x, y). P x \<and> y = None) (assocs f))"
   apply (subst assocs_dom_comp [symmetric])
   apply (subst empty_set_is_null)
   apply (simp add: null_def)
   done


lemma dom_hd_assocsD:
  fixes P
  defines "filter_assocs f \<equiv> filter (\<lambda>(x,y). P x \<and> y = None) (assocs f)"
  assumes d: "- dom f \<inter> Collect P \<noteq> {}"
  shows "fst (hd (filter_assocs f)) \<notin> dom f \<and> P (fst (hd (filter_assocs f)))"
proof -
  from d  have "\<not>null (filter_assocs f)"
    unfolding filter_assocs_def
    by (simp add: assocs_empty_dom_comp)
  hence "hd (filter_assocs f) \<in> set (filter_assocs f)"
    by (clarsimp simp: null_def neq_Nil_conv)
  thus ?thesis
    unfolding filter_assocs_def
    by (clarsimp simp: in_assocs_is_fun)
qed


lemma check_vp_wpR [wp]:
  "\<lbrace>\<lambda>s. vmsz_aligned w sz \<longrightarrow> P () s\<rbrace> 
  check_vp_alignment sz w \<lbrace>P\<rbrace>, -"
  apply (simp add: check_vp_alignment_def unlessE_whenE cong: vmpage_size.case_cong)
  apply (rule hoare_pre)
   apply (wp hoare_whenE_wp|wpc)+
  apply (simp add: vmsz_aligned_def)
  done


lemma check_vp_inv: "\<lbrace>P\<rbrace> check_vp_alignment sz w \<lbrace>\<lambda>_. P\<rbrace>"
  apply (simp add: check_vp_alignment_def unlessE_whenE cong: vmpage_size.case_cong)
  apply (rule hoare_pre)
   apply (wp hoare_whenE_wp|wpc)+
  apply simp
  done


lemma p2_low_bits_max:
  "(2 ^ asid_low_bits - 1) = (max_word :: 10 word)"
  by (simp add: asid_low_bits_def max_word_def)

lemma dom_ucast_eq:
  "(- dom (\<lambda>a::10 word. p (ucast a::word32)) \<inter> {x. x \<le> 2 ^ asid_low_bits - 1 \<and> ucast x + y \<noteq> 0} = {}) =
   (- dom p \<inter> {x. x \<le> 2 ^ asid_low_bits - 1 \<and> x + y \<noteq> 0} = {})"
  apply safe
   apply clarsimp
   apply (rule ccontr)
   apply (erule_tac x="ucast x" in WordLemmaBucket.in_emptyE)
   apply (clarsimp simp: p2_low_bits_max)
   apply (rule conjI)
    apply (clarsimp simp: ucast_ucast_mask)
    apply (subst (asm) less_mask_eq)
    apply (rule word_less_sub_le [THEN iffD1])
      apply (simp add: word_bits_def)
     apply (simp add: asid_low_bits_def)
    apply simp
   apply (clarsimp simp: ucast_ucast_mask)
   apply (subst (asm) less_mask_eq)
   apply (rule word_less_sub_le [THEN iffD1])
     apply (simp add: word_bits_def)
    apply (simp add: asid_low_bits_def)
   apply simp
  apply (clarsimp simp: p2_low_bits_max)
  apply (rule ccontr)
  apply simp
  apply (erule_tac x="ucast x" in WordLemmaBucket.in_emptyE)
  apply clarsimp
  apply (rule conjI, blast)
  apply (rule word_less_sub_1)
  apply (rule order_less_le_trans)
  apply (rule ucast_less, simp)
  apply (simp add: asid_low_bits_def)
  done

lemma asid_high_bits_max_word:
  "(2 ^ asid_high_bits - 1 :: word8) = max_word"
  by (simp add: asid_high_bits_def max_word_def) 

lemma dom_ucast_eq_8:
  "(- dom (\<lambda>a::word8. p (ucast a::word32)) \<inter> {x. x \<le> 2 ^ asid_high_bits - 1} = {}) =
   (- dom p \<inter> {x. x \<le> 2 ^ asid_high_bits - 1} = {})"
  apply safe
   apply clarsimp
   apply (rule ccontr)
   apply (erule_tac x="ucast x" in WordLemmaBucket.in_emptyE)
   apply (clarsimp simp: asid_high_bits_max_word)
   apply (clarsimp simp: ucast_ucast_mask)
   apply (subst (asm) less_mask_eq)
   apply (rule word_less_sub_le [THEN iffD1])
     apply (simp add: word_bits_def)
    apply (simp add: asid_high_bits_def)
   apply simp
  apply (clarsimp simp: asid_high_bits_max_word)
  apply (rule ccontr)
  apply simp
  apply (erule_tac x="ucast x" in WordLemmaBucket.in_emptyE)
  apply clarsimp
  apply (rule conjI, blast)
  apply (rule word_less_sub_1)
  apply (rule order_less_le_trans)
  apply (rule ucast_less, simp)
  apply (simp add: asid_high_bits_def)
  done

lemma ucast_assocs:
  "len_of TYPE('a) < len_of TYPE('b) \<Longrightarrow>
   assocs (fn o (ucast :: ('a :: len) word \<Rightarrow> ('b :: len) word))
     = map (\<lambda>(x, y). (ucast x, y)) (filter (\<lambda>(x, y). x < 2 ^ len_of TYPE('a)) (assocs fn))"
  apply (simp add: assocs_def enum_word_def
                   split_def filter_map)
  apply (rule map_cong)
   apply (simp add: o_def)
   apply (rule trans [OF _ filter_cong [OF refl]],
          rule sym, rule filter_to_shorter_upto)
    apply simp
   apply (rule iffI)
    apply (subst word_unat_power, rule of_nat_mono_maybe)
     apply simp
    apply assumption
   apply (simp add: word_less_nat_alt word_unat.Abs_inverse unats_def unat_power_lower
                    del: of_nat_power)
  apply clarsimp
  apply (simp add: word_less_nat_alt word_unat.Abs_inverse unats_def unat_power_lower del: of_nat_power)
  apply (simp add: ucast_of_nat_small)
  done


lemma ucast_le_migrate:
  fixes x :: "('a :: len) word"
  fixes y :: "('b :: len) word"
  shows
  "\<lbrakk> y < 2 ^ (size x); size x < size y \<rbrakk> \<Longrightarrow>
    (ucast x \<le> y) = (x \<le> ucast y)"
  apply (simp add: word_le_def ucast_def)
  apply (subst word_uint.Abs_inverse)
   apply (simp add: uints_num word_size)
   apply (rule order_less_le_trans, rule uint_lt2p)
   apply simp
  apply (subst word_uint.Abs_inverse)
   apply (simp add: uints_num word_size word_less_alt
                    uint_2p_alt)
  apply simp
  done


lemma ucast_fst_hd_assocs:
  "- dom (\<lambda>x. pool (ucast (x::10 word)::word32)) \<inter> {x. x \<le> 2 ^ asid_low_bits - 1 \<and> ucast x + (w::word32) \<noteq> 0} \<noteq> {}
  \<Longrightarrow> 
  fst (hd [(x, y)\<leftarrow>assocs pool . x \<le> 2 ^ asid_low_bits - 1 \<and> x + w \<noteq> 0 \<and> y = None]) =
  ucast (fst (hd [(x, y)\<leftarrow>assocs (\<lambda>a::10 word. pool (ucast a)) . 
                          x \<le> 2 ^ asid_low_bits - 1 \<and> 
                          ucast x + w \<noteq> 0 \<and> y = None]))"
  apply (simp add: ucast_assocs[unfolded o_def])
  apply (simp add: filter_map split_def)
  apply (simp cong: conj_cong add: ucast_ucast_len)
  apply (simp add: asid_low_bits_def minus_one_norm)
  apply (simp add: ord_le_eq_trans [OF word_n1_ge])
  apply (simp add: word_le_make_less)
  apply (subgoal_tac "P" for P)  (* cut_tac but more awesome *)
   apply (subst hd_map, assumption)
   apply simp
   apply (rule sym, rule ucast_ucast_len)
   apply (drule hd_in_set)
   apply simp
  apply (simp add: assocs_empty_dom_comp null_def split_def)
  apply (simp add: ucast_assocs[unfolded o_def] filter_map split_def)
  apply (simp cong: conj_cong add: ucast_ucast_len)
  done


crunch typ_at [wp]: perform_page_table_invocation, perform_page_invocation,
         perform_asid_pool_invocation, perform_page_directory_invocation "\<lambda>s. P (typ_at T p s)"
  (wp: crunch_wps)


lemmas perform_page_table_invocation_typ_ats [wp] =
  abs_typ_at_lifts [OF perform_page_table_invocation_typ_at]


lemmas perform_page_directory_invocation_typ_ats [wp] =
  abs_typ_at_lifts [OF perform_page_directory_invocation_typ_at]


lemmas perform_page_invocation_typ_ats [wp] =
  abs_typ_at_lifts [OF perform_page_invocation_typ_at]


lemmas perform_asid_pool_invocation_typ_ats [wp] =
  abs_typ_at_lifts [OF perform_asid_pool_invocation_typ_at]

lemma obj_at_delete_objects:
  "\<lbrace>\<lambda>s. Q (obj_at (P (interrupt_irq_node s) (arch_state s)) r s) \<and>
        r \<notin> {ptr..ptr + 2 ^ bits - 1}\<rbrace>
   delete_objects ptr bits
   \<lbrace>\<lambda>_ s. Q (obj_at (P (interrupt_irq_node s) (arch_state s)) r s)\<rbrace>"
  apply (simp add: delete_objects_def do_machine_op_def split_def)
  apply wp
  apply (simp add: detype_machine_state_update_comm)
  done


lemma perform_asid_control_invocation_tcb_at:
  "\<lbrace>invs and valid_aci aci and st_tcb_at active p and
    K (\<forall>w a b c. aci = asid_control_invocation.MakePool w a b c \<longrightarrow> w \<noteq> p)\<rbrace> 
  perform_asid_control_invocation aci 
  \<lbrace>\<lambda>rv. tcb_at p\<rbrace>"
  apply (simp add: perform_asid_control_invocation_def)
  apply (cases aci)
  apply clarsimp
  apply (wp |simp)+  
    apply (wp obj_at_delete_objects retype_region_obj_at_other2  hoare_vcg_const_imp_lift|assumption)+
  apply (intro impI conjI)
    apply (clarsimp simp: retype_addrs_def obj_bits_api_def default_arch_object_def image_def ptr_add_def)
   apply (clarsimp simp: st_tcb_at_tcb_at)+
  apply (frule st_tcb_ex_cap)
    apply fastforce
   apply (clarsimp split: Structures_A.thread_state.splits)
   apply auto[1]
  apply (clarsimp simp: ex_nonz_cap_to_def valid_aci_def)
  apply (frule invs_untyped_children)
  apply (clarsimp simp:cte_wp_at_caps_of_state)
  apply (erule_tac ptr="(aa,ba)" in untyped_children_in_mdbE[where P="\<lambda>c. t \<in> zobj_refs c" for t])
      apply (simp add: cte_wp_at_caps_of_state)
     apply simp
    apply (simp add:cte_wp_at_caps_of_state)
    apply fastforce
   apply (clarsimp simp: zobj_refs_to_obj_refs)
   apply (erule(1) in_empty_interE)
    apply (clarsimp simp:page_bits_def)
  apply simp
  done



lemma ucast_asid_high_btis_of_le [simp]:
  "ucast (asid_high_bits_of w) \<le> (2 ^ asid_high_bits - 1 :: word32)"
  apply (simp add: asid_high_bits_of_def)
  apply (rule word_less_sub_1)
  apply (rule order_less_le_trans)
  apply (rule ucast_less)
   apply simp
  apply (simp add: asid_high_bits_def)
  done


lemma invoke_arch_tcb:
  "\<lbrace>invs and valid_arch_inv ai and st_tcb_at active tptr\<rbrace> 
  arch_perform_invocation ai 
  \<lbrace>\<lambda>rv. tcb_at tptr\<rbrace>"
  apply (simp add: arch_perform_invocation_def)
  apply (cases ai, simp_all)
     apply (wp, clarsimp simp: st_tcb_at_tcb_at)+
   defer
   apply (wp, clarsimp simp: st_tcb_at_tcb_at)
  apply (wp perform_asid_control_invocation_tcb_at)
  apply (clarsimp simp add: valid_arch_inv_def)
  apply (clarsimp simp: valid_aci_def)
  apply (frule st_tcb_ex_cap)
    apply fastforce
   apply (clarsimp split: Structures_A.thread_state.splits)
   apply auto[1]
  apply (clarsimp simp: ex_nonz_cap_to_def)
  apply (frule invs_untyped_children)
  apply (clarsimp simp:cte_wp_at_caps_of_state)
  apply (erule_tac ptr="(aa,ba)" in untyped_children_in_mdbE[where P="\<lambda>c. t \<in> zobj_refs c" for t])
      apply (simp add: cte_wp_at_caps_of_state)+
     apply fastforce
   apply (clarsimp simp: zobj_refs_to_obj_refs cte_wp_at_caps_of_state)
   apply (drule_tac p="(aa,ba)" in caps_of_state_valid_cap, fastforce)
   apply (clarsimp simp: valid_cap_def cap_aligned_def) 
   apply (drule_tac x=tptr in base_member_set, simp)
    apply (simp add: pageBits_def field_simps del: atLeastAtMost_iff)
   apply (metis (no_types) orthD1 x_power_minus_1)
  apply simp
  done


locale asid_update =
  fixes ap asid s s'
  assumes ko: "ko_at (ArchObj (arch_kernel_obj.ASIDPool empty)) ap s"
  assumes empty: "arm_asid_table (arch_state s) asid = None"
  defines "s' \<equiv> s\<lparr>arch_state := arch_state s\<lparr>arm_asid_table := arm_asid_table (arch_state s)(asid \<mapsto> ap)\<rparr>\<rparr>"
begin
lemma vs_lookup1' [simp]:
  "vs_lookup1 s' = vs_lookup1 s"
  by (simp add: vs_lookup1_def s'_def)


lemma vs_lookup_pages1' [simp]:
  "vs_lookup_pages1 s' = vs_lookup_pages1 s"
  by (simp add: vs_lookup_pages1_def s'_def)


lemma vs_asid_refs' [simp]:
  "vs_asid_refs (arm_asid_table (arch_state s')) = 
  vs_asid_refs (arm_asid_table (arch_state s)) \<union> {([VSRef (ucast asid) None], ap)}"
  apply (simp add: s'_def)
  apply (rule set_eqI)
  apply (rule iffI)
   apply (auto simp: vs_asid_refs_def split: split_if_asm)[1]
  apply clarsimp
  apply (erule disjE)
   apply (auto simp: vs_asid_refs_def)[1]
  apply (subst (asm) vs_asid_refs_def)
  apply (clarsimp dest!: graph_ofD) 
  apply (rule vs_asid_refsI)
  apply (clarsimp simp: empty)
  done
  

lemma vs_lookup':
  "vs_lookup s' = vs_lookup s \<union> {([VSRef (ucast asid) None], ap)}"
  using ko
  apply (simp add: vs_lookup_def)
  apply (rule rtrancl_insert)
  apply (clarsimp simp: vs_lookup1_def obj_at_def vs_refs_def)
  done


lemma vs_lookup_pages':
  "vs_lookup_pages s' = vs_lookup_pages s \<union> {([VSRef (ucast asid) None], ap)}"
  using ko
  apply (simp add: vs_lookup_pages_def)
  apply (rule rtrancl_insert)
  apply (clarsimp simp: vs_lookup_pages1_def obj_at_def vs_refs_pages_def)
  done


lemma arch_obj [simp]:
  "valid_arch_obj ao s' = valid_arch_obj ao s"
  by (cases ao, simp_all add: s'_def)


lemma obj_at [simp]:
  "obj_at P p s' = obj_at P p s"
  by (simp add: s'_def)


lemma arch_objs':
  "valid_arch_objs s \<Longrightarrow> valid_arch_objs s'"
  using ko
  apply (clarsimp simp: valid_arch_objs_def vs_lookup')
  apply (fastforce simp: obj_at_def)
  done


lemma global_objs':
  "valid_global_objs s \<Longrightarrow> valid_global_objs s'"
  apply (clarsimp simp: valid_global_objs_def valid_ao_at_def)
  apply (auto simp: s'_def)
  done


lemma caps_of_state_s':
  "caps_of_state s' = caps_of_state s"
  by (rule caps_of_state_pspace, simp add: s'_def)


lemma valid_vs_lookup':
  "\<lbrakk> valid_vs_lookup s; 
     \<exists>ptr cap. caps_of_state s ptr = Some cap
     \<and> ap \<in> obj_refs cap \<and> vs_cap_ref cap = Some [VSRef (ucast asid) None] \<rbrakk>
  \<Longrightarrow> valid_vs_lookup s'"
  by (clarsimp simp: valid_vs_lookup_def caps_of_state_s' vs_lookup_pages')


lemma valid_table_caps':
  "\<lbrakk> valid_table_caps s \<rbrakk>
        \<Longrightarrow> valid_table_caps s'"
  apply (simp add: valid_table_caps_def caps_of_state_s')
  apply (simp add: s'_def)
  done


lemma valid_arch_caps:
  "\<lbrakk> valid_arch_caps s; 
     \<exists>ptr cap. caps_of_state s ptr = Some cap
     \<and> ap \<in> obj_refs cap \<and> vs_cap_ref cap = Some [VSRef (ucast asid) None] \<rbrakk>
  \<Longrightarrow> valid_arch_caps s'"
  by (simp add: valid_arch_caps_def caps_of_state_s'
                valid_table_caps' valid_vs_lookup')


lemma valid_asid_map':
  "valid_asid_map s \<Longrightarrow> valid_asid_map s'" 
  using empty
  apply (clarsimp simp: valid_asid_map_def s'_def)
  apply (drule bspec, blast)
  apply (clarsimp simp: pd_at_asid_def)
  apply (drule vs_lookup_2ConsD)
  apply clarsimp
  apply (erule vs_lookup_atE)
  apply (drule vs_lookup1D)
  apply clarsimp
  apply (rule vs_lookupI[rotated])
   apply (rule r_into_rtrancl)
   apply (rule vs_lookup1I)
     apply (fastforce simp: obj_at_def)
    apply assumption
   apply simp
  apply (clarsimp simp: vs_asid_refs_def graph_of_def)
  apply fastforce
  done

end
lemma valid_arch_state_strg:
  "valid_arch_state s \<and> ap \<notin> ran (arm_asid_table (arch_state s)) \<and> asid_pool_at ap s \<longrightarrow>
   valid_arch_state (s\<lparr>arch_state := arch_state s\<lparr>arm_asid_table := arm_asid_table (arch_state s)(asid \<mapsto> ap)\<rparr>\<rparr>)"
  apply (clarsimp simp: valid_arch_state_def)
  apply (clarsimp simp: valid_asid_table_def ran_def)
  apply (fastforce intro!: inj_on_fun_updI)
  done


lemma valid_vs_lookup_at_upd_strg:
  "valid_vs_lookup s \<and> 
   ko_at (ArchObj (arch_kernel_obj.ASIDPool empty)) ap s \<and>
   arm_asid_table (arch_state s) asid = None \<and>
   (\<exists>ptr cap. caps_of_state s ptr = Some cap \<and> ap \<in> obj_refs cap \<and> 
              vs_cap_ref cap = Some [VSRef (ucast asid) None])
   \<longrightarrow>
   valid_vs_lookup (s\<lparr>arch_state := arch_state s\<lparr>arm_asid_table := arm_asid_table (arch_state s)(asid \<mapsto> ap)\<rparr>\<rparr>)"
  apply clarsimp 
  apply (subgoal_tac "asid_update ap asid s")
   prefer 2
   apply unfold_locales[1]
    apply assumption+
  apply (erule (1) asid_update.valid_vs_lookup')
  apply fastforce
  done

(* FIXME: move *)
crunch arch [wp]: retype_region "\<lambda>s. P (arch_state s)"
  (simp: crunch_simps)

declare detype_arch_state [simp]

lemma retype_region_ap:
  "\<lbrace>\<top>\<rbrace>
  retype_region ap 1 0 (ArchObject ASIDPoolObj) 
  \<lbrace>\<lambda>_. ko_at (ArchObj (arch_kernel_obj.ASIDPool empty)) ap\<rbrace>"
  apply (rule hoare_post_imp)
   prefer 2
   apply (rule retype_region_obj_at)
    apply simp
   apply simp
  apply (clarsimp simp: retype_addrs_def obj_bits_api_def default_arch_object_def)
  apply (clarsimp simp: obj_at_def default_object_def default_arch_object_def)
  done

lemma retype_region_ap':
  "\<lbrace>\<top>\<rbrace> retype_region ap 1 0 (ArchObject ASIDPoolObj) \<lbrace>\<lambda>rv. asid_pool_at ap\<rbrace>"
  apply (rule hoare_strengthen_post, rule retype_region_ap)
  apply (clarsimp simp: a_type_def elim!: obj_at_weakenE)
  done

lemma no_cap_to_obj_with_diff_ref_null_filter:
  "no_cap_to_obj_with_diff_ref cap S
     = (\<lambda>s. \<forall>c \<in> ran (null_filter (caps_of_state s) |` (- S)).
             obj_refs c = obj_refs cap
                 \<longrightarrow> table_cap_ref c = table_cap_ref cap)"
  apply (simp add: no_cap_to_obj_with_diff_ref_def
                   ball_ran_eq cte_wp_at_caps_of_state)
  apply (simp add: Ball_def)
  apply (intro iff_allI ext)
  apply (simp add: restrict_map_def null_filter_def)
  apply (auto dest!: obj_ref_none_no_asid[rule_format]
               simp: table_cap_ref_def)
  done

lemma retype_region_no_cap_to_obj:
  "\<lbrace>valid_pspace and valid_mdb 
             and caps_overlap_reserved {ptr..ptr + 2 ^ obj_bits_api ty us - 1}
             and caps_no_overlap ptr sz
             and pspace_no_overlap ptr sz
             and no_cap_to_obj_with_diff_ref cap S
             and K (ty = Structures_A.CapTableObject \<longrightarrow> 0 < us)
             and K (range_cover ptr sz (obj_bits_api ty us) 1) \<rbrace>
     retype_region ptr 1 us ty
   \<lbrace>\<lambda>rv. no_cap_to_obj_with_diff_ref cap S\<rbrace>"
  apply (rule hoare_gen_asm)+
  apply (simp add: no_cap_to_obj_with_diff_ref_null_filter)
  apply (wp retype_region_caps_of | simp)+
  apply fastforce
  done

lemma valid_table_caps_asid_upd [iff]:
  "valid_table_caps (s\<lparr>arch_state := (arm_asid_table_update f (arch_state s))\<rparr>) =
   valid_table_caps s"
  by (simp add: valid_table_caps_def)


lemma vs_asid_ref_upd:
  "([VSRef (ucast (asid_high_bits_of asid')) None] \<rhd> ap')
    (s\<lparr>arch_state := arch_state s\<lparr>arm_asid_table := arm_asid_table (arch_state s)(asid_high_bits_of asid \<mapsto> ap)\<rparr>\<rparr>)
  = (if asid_high_bits_of asid' = asid_high_bits_of asid 
    then ap' = ap
    else ([VSRef (ucast (asid_high_bits_of asid')) None] \<rhd> ap') s)"
  by (fastforce intro: vs_lookup_atI elim: vs_lookup_atE)


lemma vs_asid_ref_eq:
  "([VSRef (ucast asid) None] \<rhd> ap) s    
  = (arm_asid_table (arch_state s) asid = Some ap)"
  by (fastforce elim: vs_lookup_atE intro: vs_lookup_atI)


lemma set_free_index_final_cap:
  "\<lbrace>\<lambda>s. P (is_final_cap' cap s) \<and> cte_wp_at (op = src_cap) src s\<rbrace>
   set_cap (free_index_update f src_cap) src 
   \<lbrace>\<lambda>rv s. P (is_final_cap' cap s) \<rbrace>"
  apply (simp add:is_final_cap'_def2)
  apply (clarsimp simp:valid_def)
  apply (drule set_cap_caps_of_state_monad)
  apply (erule subst[rotated])
  apply (rule_tac f = P in arg_cong)
  apply (subgoal_tac "\<And>slot. (cte_wp_at (\<lambda>c. obj_irq_refs cap \<inter> obj_irq_refs c \<noteq> {}) slot s
          = cte_wp_at (\<lambda>c. obj_irq_refs cap \<inter> obj_irq_refs c \<noteq> {}) slot b)")
   apply simp
  apply (clarsimp split:cap.splits 
         simp:cte_wp_at_caps_of_state free_index_update_def
              obj_irq_refs_def)
  done

lemma set_cap_orth:
  "\<lbrace>\<lambda>s. P s \<and> Q cap' s\<rbrace> set_cap cap src \<lbrace>\<lambda>rv s. Q cap' s\<rbrace> \<Longrightarrow>
   \<lbrace>\<lambda>s. P s \<and> src\<noteq> dest \<and> (cte_wp_at (op = cap') dest s \<longrightarrow> Q cap' s)\<rbrace>
   set_cap cap src 
   \<lbrace>\<lambda>rv s. cte_wp_at (op = cap') dest s \<longrightarrow> Q cap' s\<rbrace>"
   apply (clarsimp simp:valid_def cte_wp_at_caps_of_state)
   apply (drule_tac x = s in spec)
   apply (frule set_cap_caps_of_state_monad)
   apply clarsimp
   apply (drule(1) bspec)
   apply clarsimp
   done

lemma set_cap_reachable_pg_cap:
  "\<lbrace>\<lambda>s. P (reachable_pg_cap cap s)\<rbrace> set_cap x y \<lbrace>\<lambda>_ s. P (reachable_pg_cap cap s)\<rbrace>"
  by (unfold reachable_pg_cap_def, wp hoare_vcg_ex_lift set_cap_vs_lookup_pages)

lemma empty_table_caps_of:
  "empty_table S ko \<Longrightarrow> caps_of ko = {}"
  by (auto simp: caps_of_def cap_of_def empty_table_def a_type_def
          split: Structures_A.kernel_object.split split_if_asm)

lemma set_cap_empty_tables[wp]:
  "\<lbrace>\<lambda>s. P (obj_at (empty_table (set (arm_global_pts (arch_state s)))) p s)\<rbrace>
     set_cap cap cref
   \<lbrace>\<lambda>rv s. P (obj_at (empty_table (set (arm_global_pts (arch_state s)))) p s)\<rbrace>"
  apply (rule hoare_pre)
   apply (rule hoare_use_eq [where f=arch_state, OF set_cap_arch])
   apply (wp set_cap_obj_at_impossible)
  apply (clarsimp simp: empty_table_caps_of)
  done

lemma cap_insert_simple_arch_caps_ap:
  "\<lbrace>valid_arch_caps and (\<lambda>s. cte_wp_at (safe_parent_for (cdt s) src cap) src s)
     and no_cap_to_obj_with_diff_ref cap {dest} 
     and (\<lambda>s. arm_asid_table (arch_state s) (asid_high_bits_of asid) = None)
     and ko_at (ArchObj (arch_kernel_obj.ASIDPool empty)) ap 
     and K (cap = cap.ArchObjectCap (arch_cap.ASIDPoolCap ap asid)) \<rbrace>
     cap_insert cap src dest
   \<lbrace>\<lambda>rv s. valid_arch_caps (s\<lparr>arch_state := arch_state s
                       \<lparr>arm_asid_table := arm_asid_table (arch_state s)(asid_high_bits_of asid \<mapsto> ap)\<rparr>\<rparr>)\<rbrace>"
  apply (simp add: cap_insert_def update_cdt_def set_cdt_def valid_arch_caps_def 
    set_untyped_cap_as_full_def bind_assoc) 
  apply (strengthen valid_vs_lookup_at_upd_strg)
  apply (wp get_cap_wp set_cap_valid_vs_lookup set_cap_arch_obj
            set_cap_valid_table_caps hoare_vcg_all_lift 
          | simp split del: split_if)+
       apply (rule_tac P = "cte_wp_at (op = src_cap) src" in set_cap_orth)
       apply (wp hoare_vcg_imp_lift hoare_vcg_ball_lift set_free_index_final_cap 
                 hoare_vcg_disj_lift set_cap_reachable_pg_cap set_cap_vs_lookup_pages 
              | clarsimp)+
      apply (wp set_cap_arch_obj set_cap_valid_table_caps hoare_vcg_ball_lift
                get_cap_wp static_imp_wp)
  apply (clarsimp simp: cte_wp_at_caps_of_state is_cap_simps)
  apply (rule conjI)
   apply (clarsimp simp: vs_cap_ref_def)
   apply (rule_tac x="fst dest" in exI)
   apply (rule_tac x="snd dest" in exI)
   apply simp
  apply (rule conjI)
   apply (simp add: unique_table_caps_def is_cap_simps)
  apply (subst unique_table_refs_def)
  apply (intro allI impI)
  apply (simp split: split_if_asm)
    apply (simp add: no_cap_to_obj_with_diff_ref_def cte_wp_at_caps_of_state)
   apply (simp add: no_cap_to_obj_with_diff_ref_def cte_wp_at_caps_of_state)
  apply (erule (3) unique_table_refsD)
  done

lemma valid_irq_node_arch_udapte [iff]:
  "valid_irq_node (arch_state_update f s) = valid_irq_node s"
  by (simp add: valid_irq_node_def)


lemma valid_asid_map_asid_upd_strg:
  "valid_asid_map s \<and> 
   ko_at (ArchObj (arch_kernel_obj.ASIDPool empty)) ap s \<and>
   arm_asid_table (arch_state s) asid = None \<longrightarrow>
   valid_asid_map (s\<lparr>arch_state := arch_state s\<lparr>arm_asid_table := arm_asid_table (arch_state s)(asid \<mapsto> ap)\<rparr>\<rparr>)"
  apply clarsimp 
  apply (subgoal_tac "asid_update ap asid s")
   prefer 2
   apply unfold_locales[1]
    apply assumption+
  apply (erule (1) asid_update.valid_asid_map')
  done

lemma valid_arch_objs_asid_upd_strg:
  "valid_arch_objs s \<and> 
   ko_at (ArchObj (arch_kernel_obj.ASIDPool empty)) ap s \<and>
   arm_asid_table (arch_state s) asid = None \<longrightarrow>
   valid_arch_objs (s\<lparr>arch_state := arch_state s\<lparr>arm_asid_table := arm_asid_table (arch_state s)(asid \<mapsto> ap)\<rparr>\<rparr>)"
  apply clarsimp 
  apply (subgoal_tac "asid_update ap asid s")
   prefer 2
   apply unfold_locales[1]
    apply assumption+
  apply (erule (1) asid_update.arch_objs')
  done


lemma valid_global_objs_asid_upd_strg:
  "valid_global_objs s \<and> 
   ko_at (ArchObj (arch_kernel_obj.ASIDPool empty)) ap s \<and>
   arm_asid_table (arch_state s) asid = None \<longrightarrow>
   valid_global_objs (s\<lparr>arch_state := arch_state s\<lparr>arm_asid_table := arm_asid_table (arch_state s)(asid \<mapsto> ap)\<rparr>\<rparr>)"
  by clarsimp 


lemma valid_kernel_mappings_asid_upd [iff]:
  "valid_kernel_mappings
   (s\<lparr>arch_state := arch_state s\<lparr>arm_asid_table := arm_asid_table (arch_state s)(asid_high_bits_of asid \<mapsto> ap)\<rparr>\<rparr>)
  = valid_kernel_mappings s"
  by (simp add: valid_kernel_mappings_def)


lemma cap_insert_ap_invs:
  "\<lbrace>invs and valid_cap cap and tcb_cap_valid cap dest and
    ex_cte_cap_wp_to (appropriate_cte_cap cap) dest and
    cte_wp_at (\<lambda>c. c = cap.NullCap) dest and 
    no_cap_to_obj_with_diff_ref cap {dest} and
    (\<lambda>s. cte_wp_at (safe_parent_for (cdt s) src cap) src s) and
    K (cap = cap.ArchObjectCap (arch_cap.ASIDPoolCap ap asid)) and 
   (\<lambda>s. \<forall>irq \<in> cap_irqs cap. irq_issued irq s) and 
   ko_at (ArchObj (arch_kernel_obj.ASIDPool empty)) ap and
   (\<lambda>s. ap \<notin> ran (arm_asid_table (arch_state s)) \<and> 
        arm_asid_table (arch_state s) (asid_high_bits_of asid) = None)\<rbrace>
  cap_insert cap src dest 
  \<lbrace>\<lambda>rv s. invs (s\<lparr>arch_state := arch_state s
                       \<lparr>arm_asid_table := (arm_asid_table \<circ> arch_state) s(asid_high_bits_of asid \<mapsto> ap)\<rparr>\<rparr>)\<rbrace>"
  apply (simp add: invs_def valid_state_def valid_pspace_def)
  apply (strengthen valid_arch_state_strg valid_arch_objs_asid_upd_strg 
                    valid_asid_map_asid_upd_strg )
  apply (simp cong: conj_cong)
  apply (rule hoare_pre) 
   apply (wp cap_insert_simple_mdb cap_insert_iflive 
             cap_insert_zombies cap_insert_ifunsafe 
             cap_insert_valid_global_refs cap_insert_idle
             valid_irq_node_typ cap_insert_simple_arch_caps_ap)
  apply (clarsimp simp: is_simple_cap_def cte_wp_at_caps_of_state is_cap_simps)
  apply (drule safe_parent_cap_range)
  apply simp
  apply (rule conjI)
   prefer 2
   apply (clarsimp simp: obj_at_def a_type_def)
  apply (clarsimp simp: cte_wp_at_caps_of_state)
  apply (drule_tac p="(a,b)" in caps_of_state_valid_cap, fastforce)
  apply (auto simp: obj_at_def is_tcb_def is_cap_table_def 
                    valid_cap_def [where c="cap.Zombie a b x" for a b x] 
              dest: obj_ref_is_tcb obj_ref_is_cap_table split: option.splits)
  done


lemma cte_wp_at_eq_to_op_eq:
  "cte_wp_at (\<lambda>c. c = cap) = cte_wp_at (op = cap)"
  by (simp add: cte_wp_at_caps_of_state fun_eq_iff)


lemma max_index_upd_caps_overlap_reserved:
  "\<lbrace>\<lambda>s. invs s \<and> S \<subseteq> untyped_range cap \<and>
       descendants_range_in S slot s \<and> cte_wp_at (op = cap) slot s \<and> is_untyped_cap cap\<rbrace>
  set_cap (max_free_index_update cap) slot
  \<lbrace>\<lambda>rv. caps_overlap_reserved S\<rbrace>"
  apply (rule hoare_name_pre_state)
  apply (clarsimp simp:is_cap_simps)
  apply (wp set_untyped_cap_caps_overlap_reserved)
  apply (auto simp:cte_wp_at_caps_of_state max_free_index_def)
  done

lemma max_index_upd_invs_simple:
  "\<lbrace>\<lambda>s. descendants_range_in (untyped_range cap) cref s \<and>
         pspace_no_overlap (obj_ref_of cap) (cap_bits cap) s \<and>
         invs s \<and> cte_wp_at (op = cap) cref s \<and>  is_untyped_cap cap\<rbrace>
   set_cap  (max_free_index_update cap) cref \<lbrace>\<lambda>rv. invs\<rbrace>"
  apply (rule hoare_name_pre_state)
  apply (clarsimp simp:is_cap_simps)
  apply (wp set_untyped_cap_invs_simple)
  apply (auto simp:cte_wp_at_caps_of_state max_free_index_def)
  done


lemma max_index_upd_no_cap_to:
  "\<lbrace>\<lambda>s. no_cap_to_obj_with_diff_ref cap {slot} s \<and>
        cte_wp_at (op = ucap) cref s \<and> is_untyped_cap ucap\<rbrace>
   set_cap (max_free_index_update ucap) cref
   \<lbrace>\<lambda>rv s. no_cap_to_obj_with_diff_ref cap {slot} s \<rbrace>"
  apply (clarsimp simp:no_cap_to_obj_with_diff_ref_def)
  apply (wp hoare_vcg_ball_lift set_cap_cte_wp_at_neg)
  apply (clarsimp simp:cte_wp_at_caps_of_state free_index_update_def is_cap_simps)
  apply (drule_tac x = cref in bspec)
   apply clarsimp
  apply (clarsimp simp:table_cap_ref_def)
  done

lemma perform_asid_control_invocation_st_tcb_at:
  "\<lbrace>st_tcb_at (P and (Not \<circ> inactive) and (Not \<circ> idle)) t
    and ct_active and invs and valid_aci aci\<rbrace> 
    perform_asid_control_invocation aci 
  \<lbrace>\<lambda>y. st_tcb_at P t\<rbrace>"
  apply (clarsimp simp: perform_asid_control_invocation_def split: asid_control_invocation.splits)
  apply (rename_tac word1 a b aa ba word2)
  apply (wp hoare_vcg_const_imp_lift retype_region_st_tcb_at set_cap_no_overlap|simp)+
    apply (strengthen impI[OF invs_valid_objs] impI[OF invs_psp_aligned])
    apply (clarsimp simp:conj_comms)
    apply (wp max_index_upd_invs_simple get_cap_wp)
   apply (rule hoare_name_pre_state)
   apply (subgoal_tac "is_aligned word1 page_bits")
   prefer 2
    apply (clarsimp simp: valid_aci_def cte_wp_at_caps_of_state)
    apply (drule(1) caps_of_state_valid[rotated])+
    apply (simp add:valid_cap_simps cap_aligned_def page_bits_def)
   apply (subst delete_objects_rewrite)
      apply (simp add:page_bits_def word_bits_def pageBits_def)+
    apply (simp add:is_aligned_neg_mask_eq)
   apply wp
  apply (clarsimp simp: valid_aci_def)
  apply (frule intvl_range_conv)
   apply (simp add:word_bits_def page_bits_def pageBits_def)
  apply (clarsimp simp:detype_clear_um_independent page_bits_def is_aligned_neg_mask_eq)
  apply (rule conjI)
  apply (clarsimp simp:cte_wp_at_caps_of_state)
   apply (rule pspace_no_overlap_detype)
     apply (rule caps_of_state_valid_cap)
      apply (simp add:page_bits_def)+
    apply (simp add:invs_valid_objs invs_psp_aligned)+
  apply (rule conjI)
   apply (erule st_tcb_weakenE, simp)
  apply (rule conjI)
   apply (frule st_tcb_ex_cap)
     apply clarsimp
    apply (clarsimp split: Structures_A.thread_state.splits)
   apply (clarsimp simp: ex_nonz_cap_to_def)
   apply (frule invs_untyped_children)
   apply (clarsimp simp:cte_wp_at_caps_of_state)
   apply (erule_tac ptr="(aa,ba)" in untyped_children_in_mdbE[where P="\<lambda>c. t \<in> zobj_refs c" for t])
       apply (simp add: cte_wp_at_caps_of_state)+
      apply fastforce
    apply (clarsimp simp: zobj_refs_to_obj_refs)
    apply (fastforce simp:page_bits_def)
   apply simp
  apply (clarsimp simp:obj_bits_api_def arch_kobj_size_def cte_wp_at_caps_of_state
    default_arch_object_def empty_descendants_range_in)
  apply (frule_tac cap = "(cap.UntypedCap word1 pageBits idx)"
    in detype_invariants[rotated 3],clarsimp+)
    apply (simp add:cte_wp_at_caps_of_state 
      empty_descendants_range_in descendants_range_def2)+
  apply (thin_tac "x = Some cap.NullCap" for x)+
  apply (drule(1) caps_of_state_valid_cap[OF _ invs_valid_objs])
  apply (intro conjI)
    apply (clarsimp simp:valid_cap_def cap_aligned_def range_cover_full 
     invs_psp_aligned invs_valid_objs page_bits_def)
   apply (erule pspace_no_overlap_detype)
  apply (auto simp:page_bits_def detype_clear_um_independent)
  done


lemma aci_invs':
  assumes Q_ignores_arch[simp]: "\<And>f s. Q (arch_state_update f s) = Q s"
  assumes Q_ignore_machine_state[simp]: "\<And>f s. Q (machine_state_update f s) = Q s"
  assumes Q_detype[simp]: "\<And>f s. Q (detype f s) = Q s"
  assumes cap_insert_Q: "\<And>cap src dest. \<lbrace>Q and invs and K (src \<noteq> dest)\<rbrace> 
                            cap_insert cap src dest
                           \<lbrace>\<lambda>_.Q\<rbrace>"
  assumes retype_region_Q[wp]:"\<And>a b c d. \<lbrace>Q\<rbrace> retype_region a b c d \<lbrace>\<lambda>_.Q\<rbrace>"
  assumes set_cap_Q[wp]: "\<And>a b. \<lbrace>Q\<rbrace> set_cap a b \<lbrace>\<lambda>_.Q\<rbrace>"
  shows
  "\<lbrace>invs and Q and ct_active and valid_aci aci\<rbrace> perform_asid_control_invocation aci \<lbrace>\<lambda>y s. invs s \<and> Q s\<rbrace>"
  proof -
  have cap_insert_invsQ:
       "\<And>cap src dest ap asid.
        \<lbrace>Q and (invs and valid_cap cap and tcb_cap_valid cap dest and
         ex_cte_cap_wp_to (appropriate_cte_cap cap) dest and
         cte_wp_at (\<lambda>c. c = NullCap) dest and
         no_cap_to_obj_with_diff_ref cap {dest} and
         (\<lambda>s. cte_wp_at (safe_parent_for (cdt s) src cap) src s) and
         K (cap = ArchObjectCap (ASIDPoolCap ap asid)) and
         (\<lambda>s. \<forall>irq\<in>cap_irqs cap. irq_issued irq s) and
         ko_at (ArchObj (ASIDPool Map.empty)) ap and
         (\<lambda>s. ap \<notin> ran (arm_asid_table (arch_state s)) \<and>
         arm_asid_table (arch_state s) (asid_high_bits_of asid) = None))\<rbrace>
         cap_insert cap src dest 
        \<lbrace>\<lambda>rv s.
           invs
             (s\<lparr>arch_state := arch_state s
                 \<lparr>arm_asid_table := (arm_asid_table \<circ> arch_state) s
                    (asid_high_bits_of asid \<mapsto> ap)\<rparr>\<rparr>) \<and> 
           Q
             (s\<lparr>arch_state := arch_state s
                 \<lparr>arm_asid_table := (arm_asid_table \<circ> arch_state) s
                    (asid_high_bits_of asid \<mapsto> ap)\<rparr>\<rparr>)\<rbrace>"
        apply (wp cap_insert_ap_invs)
        apply simp
        apply (rule hoare_pre)
        apply (rule cap_insert_Q)
        apply (auto simp: cte_wp_at_caps_of_state)
        done
  show ?thesis
  apply (clarsimp simp: perform_asid_control_invocation_def valid_aci_def 
    split: asid_control_invocation.splits)
  apply (rename_tac word1 a b aa ba word2)
  apply (rule hoare_pre)
   apply (wp hoare_vcg_const_imp_lift)
     apply (wp cap_insert_invsQ hoare_vcg_ex_lift
             | simp)+
    apply (simp add: valid_cap_def |
           strengthen real_cte_tcb_valid safe_parent_strg
                      invs_vobjs_strgs
                      ex_cte_cap_to_cnode_always_appropriate_strg)+
    apply (wp hoare_vcg_const_imp_lift set_free_index_invs
              retype_region_plain_invs[where sz = pageBits]
              retype_cte_wp_at[where sz = pageBits] hoare_vcg_ex_lift
              retype_region_obj_at_other3[where P="is_cap_table n" and sz = pageBits for n]
              retype_region_ex_cte_cap_to[where sz = pageBits]
              retype_region_ap[simplified]
              retype_region_ap'[simplified] 
              retype_region_no_cap_to_obj[where sz = pageBits,simplified]
               | simp)+
    apply (strengthen impI[OF invs_valid_objs] impI[OF invs_psp_aligned]
           impI[OF invs_mdb] impI[OF invs_valid_pspace])
    apply (clarsimp simp: valid_aci_def is_aligned_mask [symmetric] region_in_kernel_window_def
                       valid_cap_def cap_aligned_def cte_wp_at_eq_to_op_eq
                  cong: conj_cong)
    apply (wp set_cap_caps_no_overlap set_cap_no_overlap get_cap_wp
      max_index_upd_caps_overlap_reserved max_index_upd_invs_simple
      set_cap_cte_cap_wp_to set_cap_cte_wp_at max_index_upd_no_cap_to)
    apply (rule_tac P = "is_aligned word1 page_bits" in hoare_gen_asm)
    apply (subst delete_objects_rewrite)
       apply (simp add:page_bits_def pageBits_def)
      apply (simp add:page_bits_def pageBits_def word_bits_def)
     apply (simp add:is_aligned_neg_mask_eq)
    apply wp
  apply (clarsimp simp: cte_wp_at_caps_of_state if_option_Some)
  apply (frule_tac cap = "(cap.UntypedCap word1 pageBits idx)"
    in detype_invariants[rotated 3],clarsimp+)
    apply (simp add:cte_wp_at_caps_of_state)+
   apply (simp add:descendants_range_def2 empty_descendants_range_in)
  apply (simp add:invs_mdb invs_valid_pspace invs_psp_aligned invs_valid_objs)
  apply (clarsimp dest!:caps_of_state_cteD)
  apply (frule(1) unsafe_protected[where p=t and p'=t for t])
     apply (simp add:empty_descendants_range_in)+
    apply fastforce
   apply clarsimp
  apply (frule_tac p = "(aa,ba)" in cte_wp_valid_cap)
   apply fastforce
  apply (rule conjI)
   apply (clarsimp simp:valid_cap_simps cap_aligned_def page_bits_def not_le)
  apply (clarsimp simp:detype_clear_um_independent obj_bits_api_def arch_kobj_size_def
   default_arch_object_def)
  apply (rule conjI)
   apply clarsimp
   apply (frule valid_cap_aligned)
   apply (clarsimp simp:cap_aligned_def)
   apply (frule intvl_range_conv[where bits = pageBits])
    apply (simp add:pageBits_def word_bits_def)
   apply (frule_tac ptr = word1 and sz = pageBits and idx1 = idx in
     caps_no_overlap_detype[OF descendants_range_caps_no_overlapI])
      apply (simp add:is_aligned_neg_mask_eq)
     apply (simp add:empty_descendants_range_in)
   apply (frule pspace_no_overlap_detype)
     apply (simp add:invs_psp_aligned invs_valid_objs)+
   apply (clarsimp simp:is_aligned_neg_mask_eq page_bits_def)
   apply (frule(1) ex_cte_cap_protects)
       apply (simp add:empty_descendants_range_in)
      apply fastforce
     apply (rule subset_refl)
    apply fastforce
   apply clarsimp
   apply (intro conjI impI,
     simp_all add:free_index_of_def valid_cap_simps valid_untyped_def 
     empty_descendants_range_in range_cover_full clear_um_def max_free_index_def,
     (clarsimp simp:valid_untyped_def valid_cap_simps)+)[1]
             apply (drule_tac p = "(aa,ba)" in cap_refs_in_kernel_windowD2)
              apply fastforce
             apply (clarsimp simp:region_in_kernel_window_def valid_cap_def
                   cap_aligned_def is_aligned_neg_mask_eq)
            apply clarsimp
           apply (clarsimp simp:obj_bits_api_def page_bits_def
                  default_arch_object_def arch_kobj_size_def)+
       apply (erule(1) cap_to_protected)
       apply (simp add:empty_descendants_range_in descendants_range_def2)+
      apply (clarsimp simp: no_cap_to_obj_with_diff_ref_def)
      apply (thin_tac "cte_wp_at (op = cap.NullCap) p s" for p s)
      apply (subst(asm) eq_commute,
          erule(1) untyped_children_in_mdbE[where cap="cap.UntypedCap p bits idx" for p bits idx,
                                         simplified, rotated])
        apply (simp add: is_aligned_no_overflow)
       apply simp
      apply clarsimp
     apply clarsimp+
    apply simp
   apply (thin_tac "invs s")
   apply clarsimp
   apply (drule invs_arch_state)
   apply (clarsimp simp: valid_arch_state_def valid_asid_table_def)
   apply (drule (1) bspec)
   apply clarsimp
   apply (erule notE, erule is_aligned_no_overflow)
  apply (clarsimp simp:valid_cap_simps cap_aligned_def page_bits_def)
  done
qed

lemmas aci_invs[wp] = aci_invs'[where Q=\<top>,simplified hoare_post_taut, OF refl refl refl TrueI TrueI TrueI,simplified]

lemma invoke_arch_invs[wp]:
  "\<lbrace>invs and ct_active and valid_arch_inv ai\<rbrace>
   arch_perform_invocation ai
   \<lbrace>\<lambda>rv. invs\<rbrace>"
  apply (cases ai, simp_all add: valid_arch_inv_def arch_perform_invocation_def)
  apply (wp|simp)+
  done

lemma sts_pspace_no_overlap [wp]:
  "\<lbrace>pspace_no_overlap w b\<rbrace> set_thread_state t st \<lbrace>\<lambda>rv. pspace_no_overlap w b\<rbrace>"
  by (wp pspace_no_overlap_typ_at_lift)


lemma sts_empty_pde [wp]:
  "\<lbrace>empty_pde_at p\<rbrace> set_thread_state t st \<lbrace>\<lambda>rv. empty_pde_at p\<rbrace>"
  apply (simp add: empty_pde_at_def)
  apply (rule hoare_pre)
   apply (wp hoare_vcg_ex_lift set_thread_state_ko)
  apply (clarsimp simp: is_tcb_def)
  done

lemma sts_pd_at_asid [wp]:
  "\<lbrace>pd_at_asid asid pd\<rbrace> set_thread_state t st \<lbrace>\<lambda>rv. pd_at_asid asid pd\<rbrace>"
  apply (simp add: pd_at_asid_def)
  apply wp
  done

lemma sts_same_refs_inv[wp]:
  "\<lbrace>\<lambda>s. same_refs m cap s\<rbrace> set_thread_state t st \<lbrace>\<lambda>rv s. same_refs m cap s\<rbrace>"
  by (cases m, (clarsimp simp: same_refs_def, wp)+)

lemma sts_valid_slots_inv[wp]:
  "\<lbrace>valid_slots m\<rbrace> set_thread_state t st \<lbrace>\<lambda>rv. valid_slots m\<rbrace>"
  by (cases m, (clarsimp simp: valid_slots_def, wp hoare_vcg_ball_lift sts_vs_lookup sts_typ_ats)+)

lemma sts_valid_page_inv[wp]:
"\<lbrace>valid_page_inv page_invocation\<rbrace> set_thread_state t st \<lbrace>\<lambda>rv. valid_page_inv page_invocation\<rbrace>"
  by (cases page_invocation,
       (wp hoare_vcg_const_Ball_lift hoare_vcg_ex_lift hoare_vcg_imp_lift sts_typ_ats
        | clarsimp simp: valid_page_inv_def same_refs_def 
        | wps)+)

lemma sts_valid_pdi_inv[wp]:
  "\<lbrace>valid_pdi page_directory_invocation\<rbrace> set_thread_state t st \<lbrace>\<lambda>rv. valid_pdi page_directory_invocation\<rbrace>"
  apply (cases page_directory_invocation)
   apply (wp | simp add: valid_pdi_def)+
  done
  

lemma sts_valid_arch_inv:
  "\<lbrace>valid_arch_inv ai\<rbrace> set_thread_state t st \<lbrace>\<lambda>rv. valid_arch_inv ai\<rbrace>"
  apply (cases ai, simp_all add: valid_arch_inv_def)
     apply (rename_tac page_table_invocation)
     apply (case_tac page_table_invocation, simp_all add: valid_pti_def)[1]
      apply ((wp valid_pde_lift set_thread_state_valid_cap 
                 hoare_vcg_all_lift hoare_vcg_const_imp_lift
                 hoare_vcg_ex_lift set_thread_state_ko 
                 sts_typ_ats set_thread_state_cte_wp_at
               | clarsimp simp: is_tcb_def)+)[4]
   apply (rename_tac asid_control_invocation)
   apply (case_tac asid_control_invocation)
   apply (clarsimp simp: valid_aci_def cte_wp_at_caps_of_state)
   apply (rule hoare_pre, wp hoare_vcg_ex_lift cap_table_at_typ_at)
   apply clarsimp
  apply (clarsimp simp: valid_apinv_def split: asid_pool_invocation.splits)
  apply (rule hoare_pre)
   apply (wp hoare_vcg_ex_lift set_thread_state_ko)
  apply (clarsimp simp: is_tcb_def)
  done

lemma ensure_safe_mapping_inv [wp]:
  "\<lbrace>P\<rbrace> ensure_safe_mapping m \<lbrace>\<lambda>_. P\<rbrace>"
  apply (cases m, simp_all)
   apply (case_tac a, simp)
   apply (case_tac aa, simp_all)[1]
     apply (wp mapME_x_inv_wp hoare_drop_imps get_pte_wp|wpc|simp)+
  apply (case_tac b, simp)
  apply (case_tac a, simp_all)
  apply (wp mapME_x_inv_wp hoare_drop_imps get_pde_wp|wpc|simp)+
  done

(* the induct rule matches the wrong parameters first -> crunch blows up *)
lemma create_mapping_entries_inv [wp]: 
  "\<lbrace>P\<rbrace> create_mapping_entries base vptr vmsz R A pd \<lbrace>\<lambda>_. P\<rbrace>"
  apply (induct vmsz)
     apply (simp, wp lookup_pt_slot_inv)+
  done

crunch_ignore (add: select_ext)

crunch inv [wp]: arch_decode_invocation "P"
  (wp: crunch_wps select_wp select_ext_weak_wp simp: crunch_simps)

lemma create_mappings_empty [wp]:
  "\<lbrace>\<top>\<rbrace> create_mapping_entries base vptr vmsz R A pd \<lbrace>\<lambda>m s. empty_refs m\<rbrace>, -"
  apply (cases vmsz, simp_all add: empty_refs_def)
     apply (wp|simp)+
   apply (rule hoare_pre)
    apply (wp|simp add: pde_ref_def)+
  apply (rule hoare_pre)
   apply (wp|simp add: pde_ref_def)+
  done


lemma empty_pde_atI:
  "\<lbrakk> ko_at (ArchObj (PageDirectory pd)) (p && ~~ mask pd_bits) s;
     pd (ucast (p && mask pd_bits >> 2)) = ARM_Structs_A.InvalidPDE \<rbrakk> \<Longrightarrow>
   empty_pde_at p s"
  by (fastforce simp add: empty_pde_at_def)


declare lookup_slot_for_cnode_op_cap_to [wp]


lemma shiftr_irrelevant:
  "x < 2 ^ asid_low_bits \<Longrightarrow> is_aligned (y :: word32) asid_low_bits \<Longrightarrow>
    x + y >> asid_low_bits = y >> asid_low_bits"
  apply (subst word_plus_and_or_coroll)
   apply (rule word_eqI)
   apply (clarsimp simp: is_aligned_nth)
   apply (drule(1) nth_bounded)
    apply (simp add: asid_low_bits_def word_bits_def)
   apply simp
  apply (rule word_eqI)
  apply (simp add: nth_shiftr)
  apply safe
  apply (drule(1) nth_bounded)
   apply (simp add: asid_low_bits_def word_bits_def)
  apply simp
  done


lemma create_mapping_entries_parent_for_refs:
  "\<lbrace>invs and \<exists>\<rhd> pd and page_directory_at pd
           and K (is_aligned pd pd_bits) and K (vmsz_aligned vptr pgsz)
           and K (vptr < kernel_base)\<rbrace>
    create_mapping_entries ptr vptr pgsz
                 rights attribs pd
   \<lbrace>\<lambda>rv s. \<exists>a b. cte_wp_at (parent_for_refs rv) (a, b) s\<rbrace>, -"
  apply (rule hoare_gen_asmE)+
  apply (cases pgsz, simp_all add: vmsz_aligned_def)
     apply (rule hoare_pre)
      apply wp
      apply (rule hoare_post_imp_R, rule lookup_pt_slot_cap_to)
      apply (elim exEI)
      apply (clarsimp simp: cte_wp_at_caps_of_state parent_for_refs_def)
     apply simp
    apply (rule hoare_pre)
     apply wp
     apply (rule hoare_post_imp_R)
      apply (rule lookup_pt_slot_cap_to_multiple1)
     apply (elim conjE exEI cte_wp_at_weakenE)
     apply (clarsimp simp: cte_wp_at_caps_of_state parent_for_refs_def
                           subset_iff p_0x3C_shift)
    apply simp
   apply (rule hoare_pre, wp)
   apply (clarsimp dest!:vs_lookup_pages_vs_lookupI)
   apply (drule valid_vs_lookupD, clarsimp)
   apply (simp, elim exEI)
   apply (clarsimp simp: cte_wp_at_caps_of_state parent_for_refs_def
                         lookup_pd_slot_def Let_def)
   apply (subst pd_shifting, simp add: pd_bits_def pageBits_def)
   apply (clarsimp simp: vs_cap_ref_def
                  split: cap.split_asm arch_cap.split_asm option.split_asm)
     apply (auto simp: valid_cap_def obj_at_def is_cap_simps cap_asid_def
                dest!: caps_of_state_valid_cap)[3]
     apply (frule(1) caps_of_state_valid)
     apply (clarsimp simp:valid_cap_def obj_at_def)
   apply (simp add:is_cap_simps)
  apply (rule hoare_pre, wp)
  apply (clarsimp dest!:vs_lookup_pages_vs_lookupI)
  apply (drule valid_vs_lookupD, clarsimp)
  apply (simp, elim exEI)
  apply (clarsimp simp: cte_wp_at_caps_of_state parent_for_refs_def)
  apply (rule conjI)
   apply (simp add: subset_eq)
   apply (subst p_0x3C_shift)
    apply (simp add: lookup_pd_slot_def Let_def)
    apply (erule aligned_add_aligned)
     apply (intro is_aligned_shiftl is_aligned_shiftr)
     apply simp
    apply (simp add: pd_bits_def pageBits_def)
   apply (clarsimp simp: lookup_pd_slot_add_eq)
  apply (clarsimp simp: vs_cap_ref_def
                 split: cap.split_asm arch_cap.split_asm option.split_asm)
       apply (auto simp: valid_cap_def obj_at_def is_cap_simps cap_asid_def
             dest!: caps_of_state_valid_cap)[3]
   apply (frule(1) caps_of_state_valid)
   apply (clarsimp simp:valid_cap_def obj_at_def)
  apply (simp add:is_cap_simps)
  done

lemma diminished_cte_wp_at_valid_cap:
  "cte_wp_at (diminished c) p s \<Longrightarrow> valid_objs s \<Longrightarrow> s \<turnstile> c"
  apply (drule(1) cte_wp_at_valid_objs_valid_cap)
  apply (clarsimp simp: diminished_def)
  done


lemma find_pd_for_asid_shifting_voodoo:
  "\<lbrace>pspace_aligned and valid_arch_objs\<rbrace>
     find_pd_for_asid asid
   \<lbrace>\<lambda>rv s. v >> 20 = rv + (v >> 20 << 2) && mask pd_bits >> 2\<rbrace>,-"
  apply (rule hoare_post_imp_R,
         rule find_pd_for_asid_aligned_pd)
  apply (subst pd_shifting_dual, simp)
  apply (rule word_eqI)
  apply (simp add: nth_shiftr nth_shiftl word_size)
  apply safe
  apply (drule test_bit_size)
  apply (simp add: word_size)
  done


lemma find_pd_for_asid_ref_offset_voodoo:
  "\<lbrace>pspace_aligned and valid_arch_objs and
         K (ref = [VSRef (asid && mask asid_low_bits) (Some AASIDPool),
                  VSRef (ucast (asid_high_bits_of asid)) None])\<rbrace>
      find_pd_for_asid asid
   \<lbrace>\<lambda>rv. (ref \<rhd> (rv + (v >> 20 << 2) && ~~ mask pd_bits))\<rbrace>,-"
  apply (rule hoare_gen_asmE)
  apply (rule_tac Q'="\<lambda>rv s. is_aligned rv 14 \<and> (ref \<rhd> rv) s"
               in hoare_post_imp_R)
   apply (simp add: ucast_ucast_mask
                    mask_asid_low_bits_ucast_ucast)
   apply (fold asid_low_bits_def)
   apply (rule hoare_pre, wp find_pd_for_asid_lookup_ref) 
   apply simp
  apply (simp add: pd_shifting)
  done

declare asid_high_bits_of_shift [simp]
declare mask_shift [simp]
declare word_less_sub_le [simp del]
declare ptrFormPAddr_addFromPPtr [simp]

(* FIXME: move *)
lemma valid_mask_vm_rights[simp]:
  "mask_vm_rights V R \<in> valid_vm_rights"
  by (simp add: mask_vm_rights_def)


lemma vs_lookup_and_unique_refs:
  "\<lbrakk>(ref \<rhd> p) s; caps_of_state s cptr = Some cap; table_cap_ref cap = Some ref';
    p \<in> obj_refs cap; valid_vs_lookup s; unique_table_refs (caps_of_state s)\<rbrakk>
   \<Longrightarrow> ref = ref'"
  apply (frule_tac ref=ref in valid_vs_lookupD[OF vs_lookup_pages_vs_lookupI], assumption)
  apply clarsimp
  apply (frule_tac cap'=capa in unique_table_refsD)
     apply simp+
   apply (case_tac capa, simp_all)
        apply ((case_tac cap, simp_all)+)[6]
     apply (clarsimp simp add: table_cap_ref_def vs_cap_ref_def split: cap.splits arch_cap.splits option.splits)
  done



lemma valid_global_ptsD2:
  "\<lbrakk>r \<in> set (arm_global_pts (arch_state s)); valid_global_pts s\<rbrakk>
   \<Longrightarrow> \<exists>pt. ko_at (ArchObj (PageTable pt)) r s"
  apply (clarsimp simp: valid_global_pts_def)
  apply (drule (1) bspec)
  apply (clarsimp simp: obj_at_def)
  done

lemma create_mapping_entries_same_refs:
  "\<lbrace>valid_arch_state and valid_arch_objs and valid_vs_lookup and (\<lambda>s. unique_table_refs (caps_of_state s))
    and pspace_aligned and valid_objs and valid_kernel_mappings and \<exists>\<rhd> pd and
    (\<lambda>s. \<exists>pd_cap pd_cptr. cte_wp_at (diminished pd_cap) pd_cptr s
          \<and> pd_cap = cap.ArchObjectCap (arch_cap.PageDirectoryCap pd (Some asid))) and
    page_directory_at pd and K (vaddr < kernel_base \<and> (cap = (cap.ArchObjectCap (arch_cap.PageCap p rights' pgsz (Some (asid, vaddr))))))\<rbrace>
   create_mapping_entries (Platform.addrFromPPtr p) vaddr pgsz rights attribs pd
   \<lbrace>\<lambda>rv s. same_refs rv cap s\<rbrace>,-"
  apply (rule hoare_gen_asmE)
  apply (cases pgsz, simp_all add: lookup_pt_slot_def)
     apply (wp get_pde_wp | wpc)+
     apply (clarsimp simp: lookup_pd_slot_def)
     apply (frule (1) pd_aligned)
     apply (simp add:pd_shifting vaddr_segment_nonsense2)
     apply (frule (2) valid_arch_objsD[rotated], simp)
     apply (drule bspec, simp, erule kernel_base_kernel_mapping_slots)
     apply (simp, drule (1) pt_aligned)
     apply (clarsimp simp: same_refs_def vs_cap_ref_def split: option.splits)
     apply (simp add: vaddr_segment_nonsense4 shiftl_shiftr_id
                      less_trans[OF and_mask_less'[where n=8, unfolded mask_def, simplified]]
                      word_bits_def
                      vaddr_segment_nonsense3)
     apply (rule conjI, simp add: mask_def)
     apply (clarsimp simp: cte_wp_at_caps_of_state diminished_def 
                           mask_cap_def cap_rights_update_def)
     apply (clarsimp split: Structures_A.cap.splits )
     apply (clarsimp simp: acap_rights_update_def split: ARM_Structs_A.arch_cap.splits)
     apply (frule (1) vs_lookup_and_unique_refs)
         apply (simp_all add: table_cap_ref_def obj_refs_def)[4]     
     apply (frule_tac p=pd and p'="Platform.ptrFromPAddr x" in vs_lookup_step)
      apply (clarsimp simp: vs_lookup1_def)
      apply (rule exI, erule conjI)
      apply (rule exI[where x="VSRef (vaddr >> 20) (Some APageDirectory)"])
      apply (rule conjI, rule refl)
      apply (simp add: vs_refs_def)
      apply (rule_tac x="(ucast (vaddr >> 20), Platform.ptrFromPAddr x)" in image_eqI)
       apply (simp add: ucast_ucast_len[OF shiftr_less_t2n'] mask_32_max_word graph_of_def)
      apply (clarsimp simp:graph_of_def)
      apply (frule kernel_base_kernel_mapping_slots, simp add: pde_ref_def)
     apply simp
     apply (drule (1) ref_is_unique)
     apply (rule not_kernel_slot_not_global_pt[rotated])
              apply (erule kernel_base_kernel_mapping_slots)
             apply (simp add: obj_at_def)
            apply (simp_all add: pde_ref_def valid_arch_state_def valid_objs_caps)[8]
    apply (wp get_pde_wp | wpc)+
    apply (clarsimp simp: lookup_pd_slot_def)
    apply (frule (1) pd_aligned)
    apply (simp add:pd_shifting vaddr_segment_nonsense2)
    apply (frule (2) valid_arch_objsD[rotated], simp)
    apply (drule bspec, simp, erule kernel_base_kernel_mapping_slots)
    apply (simp, drule (1) pt_aligned)
    apply (clarsimp simp: same_refs_def vs_cap_ref_def upto_enum_step_def upto_enum_word upt_conv_Cons)
    apply (simp add: vaddr_segment_nonsense4 shiftl_shiftr_id
                     less_trans[OF and_mask_less'[where n=8, unfolded mask_def, simplified]]
                     word_bits_def
                     vaddr_segment_nonsense3)
    apply (rule conjI, simp add: mask_def)
    apply (clarsimp simp: cte_wp_at_caps_of_state diminished_def 
                          mask_cap_def cap_rights_update_def)
    apply (clarsimp split: Structures_A.cap.splits )
    apply (clarsimp simp: acap_rights_update_def split: ARM_Structs_A.arch_cap.splits)
    apply (frule (1) vs_lookup_and_unique_refs)
        apply (simp_all add: table_cap_ref_def obj_refs_def)[4]     
    apply (frule_tac p=pd and p'="Platform.ptrFromPAddr x" in vs_lookup_step)
     apply (clarsimp simp: vs_lookup1_def)
     apply (rule exI, erule conjI)
     apply (rule exI[where x="VSRef (vaddr >> 20) (Some APageDirectory)"])
     apply (rule conjI, rule refl)
     apply (simp add: vs_refs_def)
     apply (rule_tac x="(ucast (vaddr >> 20), Platform.ptrFromPAddr x)" in image_eqI)
      apply (simp add: ucast_ucast_len[OF shiftr_less_t2n'] mask_32_max_word graph_of_def)
     apply (clarsimp simp:graph_of_def)
     apply (frule kernel_base_kernel_mapping_slots, simp add: pde_ref_def)
    apply simp
    apply (drule (1) ref_is_unique)
    apply (rule not_kernel_slot_not_global_pt[rotated])
             apply (erule kernel_base_kernel_mapping_slots)
            apply (simp add: obj_at_def)
           apply (simp_all add: pde_ref_def valid_arch_state_def valid_objs_caps)[8]
   apply (wp get_pde_wp returnOKE_R_wp | wpc)+
   apply (clarsimp simp: lookup_pd_slot_def)
   apply (frule (1) pd_aligned)
   apply (clarsimp simp: same_refs_def vs_cap_ref_def pde_ref_pages_def)
   apply (simp add: vaddr_segment_nonsense vaddr_segment_nonsense2)
   apply (clarsimp simp: cte_wp_at_caps_of_state diminished_def 
                         mask_cap_def cap_rights_update_def)
   apply (clarsimp split: Structures_A.cap.splits )
   apply (clarsimp simp: acap_rights_update_def split: ARM_Structs_A.arch_cap.splits)
   apply (frule (1) vs_lookup_and_unique_refs)
       apply (simp_all add: table_cap_ref_def obj_refs_def)[4]     
   apply (drule (1) ref_is_unique)
         apply (clarsimp simp: valid_arch_state_def obj_at_def dest!:valid_global_ptsD2)
        apply (simp_all add: valid_arch_state_def valid_objs_caps)[6]
   apply (wp returnOKE_R_wp | wpc)+
   apply (clarsimp simp: lookup_pd_slot_def)
   apply (frule (1) pd_aligned)
   apply (clarsimp simp: same_refs_def vs_cap_ref_def pde_ref_pages_def upto_enum_step_def upto_enum_word upt_conv_Cons)
   apply (simp add: vaddr_segment_nonsense vaddr_segment_nonsense2)
   apply (clarsimp simp: cte_wp_at_caps_of_state diminished_def 
                         mask_cap_def cap_rights_update_def)
   apply (clarsimp split: Structures_A.cap.splits )
   apply (clarsimp simp: acap_rights_update_def split: ARM_Structs_A.arch_cap.splits)
   apply (frule (1) vs_lookup_and_unique_refs)
       apply (simp_all add: table_cap_ref_def obj_refs_def)[4]     
   apply (drule (1) ref_is_unique)
         apply (clarsimp dest!: valid_global_ptsD2 simp: obj_at_def a_type_def valid_arch_state_def)
        apply (simp_all add: valid_arch_state_def valid_objs_caps)
  done

lemma create_mapping_entries_same_refs_ex:
  "\<lbrace>valid_arch_state and valid_arch_objs and valid_vs_lookup and (\<lambda>s. unique_table_refs (caps_of_state s))
    and pspace_aligned and valid_objs and valid_kernel_mappings and \<exists>\<rhd> pd and
    (\<lambda>s. \<exists>pd_cap pd_cptr asid rights'. cte_wp_at (diminished pd_cap) pd_cptr s
          \<and> pd_cap = cap.ArchObjectCap (arch_cap.PageDirectoryCap pd (Some asid))
          \<and> page_directory_at pd s \<and> vaddr < kernel_base \<and> (cap = (cap.ArchObjectCap (arch_cap.PageCap p rights' pgsz (Some (asid, vaddr))))))\<rbrace>
   create_mapping_entries (Platform.addrFromPPtr p) vaddr pgsz rights attribs pd
   \<lbrace>\<lambda>rv s. same_refs rv cap s\<rbrace>,-"
  apply (clarsimp simp: validE_R_def validE_def valid_def split: sum.split)
  apply (erule use_validE_R[OF _ create_mapping_entries_same_refs])
  apply auto
  done

lemma diminished_pd_capD:
  "diminished (cap.ArchObjectCap (arch_cap.PageDirectoryCap a b)) cap
   \<Longrightarrow> cap = (cap.ArchObjectCap (arch_cap.PageDirectoryCap a b))"
  apply (clarsimp simp: diminished_def mask_cap_def cap_rights_update_def)
  apply (clarsimp simp: acap_rights_update_def split: cap.splits arch_cap.splits)
  done

lemma diminished_pd_self:
  "diminished (cap.ArchObjectCap (arch_cap.PageDirectoryCap a b)) (cap.ArchObjectCap (arch_cap.PageDirectoryCap a b))"
  apply (clarsimp simp: diminished_def mask_cap_def cap_rights_update_def)
  apply (clarsimp simp: acap_rights_update_def split: cap.splits arch_cap.splits)
  done

lemma cte_wp_at_page_cap_weaken:
  "cte_wp_at (diminished (ArchObjectCap (PageCap word seta vmpage_size None))) slot s \<Longrightarrow>
   cte_wp_at (\<lambda>a. \<exists>p R sz m. a = ArchObjectCap (PageCap p R sz m)) slot s"
  apply (clarsimp simp: cte_wp_at_def diminished_def mask_cap_def cap_rights_update_def)
  apply (clarsimp simp: acap_rights_update_def split: cap.splits arch_cap.splits)
  done

lemma arch_decode_inv_wf[wp]:
  "\<lbrace>invs and valid_cap (cap.ArchObjectCap arch_cap) and 
    cte_wp_at (diminished (cap.ArchObjectCap arch_cap)) slot and  
    (\<lambda>s. \<forall>x \<in> set excaps. cte_wp_at (diminished (fst x)) (snd x) s)\<rbrace>
     arch_decode_invocation label args cap_index slot arch_cap excaps
   \<lbrace>valid_arch_inv\<rbrace>,-"
  apply (cases arch_cap)
      apply (rename_tac word1 word2)
      apply (simp add: arch_decode_invocation_def Let_def split_def cong: if_cong split del: split_if)
      apply (rule hoare_pre)
       apply ((wp whenE_throwError_wp check_vp_wpR ensure_empty_stronger select_wp select_ext_weak_wp|
               wpc|
               simp add: valid_arch_inv_def valid_apinv_def)+)[1]
      apply (simp add: valid_arch_inv_def valid_apinv_def)
      apply (intro allI impI ballI)
      apply (elim conjE exE)
      apply simp
      apply (clarsimp simp: dom_def neq_Nil_conv)
      apply (thin_tac "Ball S P" for S P)+
      apply (clarsimp simp: valid_cap_def)
      apply (rule conjI)
       apply (clarsimp simp: obj_at_def)
       apply (subgoal_tac "ucast (ucast xa + word2) = xa")
        apply simp
       apply (simp add: p2_low_bits_max)
       apply (simp add: is_aligned_nth)
       apply (subst word_plus_and_or_coroll)
        apply (rule word_eqI)
        apply (clarsimp simp: word_size word_bits_def nth_ucast)
        apply (drule test_bit_size)
        apply (simp add: word_size asid_low_bits_def)
       apply (rule word_eqI)
       apply (clarsimp simp: word_size word_bits_def nth_ucast)
       apply (auto simp: asid_low_bits_def)[1]
      apply (rule conjI)
       apply (clarsimp simp add: cte_wp_at_caps_of_state)
       apply (rename_tac c c')
       apply (frule_tac cap=c' in caps_of_state_valid, assumption)
       apply (drule (1) diminished_is_update)
       apply (clarsimp simp: is_pd_cap_def cap_rights_update_def
                             acap_rights_update_def)
      apply (clarsimp simp: word_neq_0_conv)
      apply (rule conjI)
       apply (subst field_simps, erule is_aligned_add_less_t2n)
         apply (simp add: asid_low_bits_def)
         apply (rule ucast_less[where 'b=10, simplified], simp)
        apply (simp add: asid_low_bits_def asid_bits_def)
       apply (simp add: asid_bits_def)
      apply (drule vs_lookup_atI)
      apply (subst asid_high_bits_of_add_ucast, assumption)
      apply assumption
     apply (simp add: arch_decode_invocation_def Let_def split_def 
                 cong: if_cong split del: split_if)
     apply (rule hoare_pre)
      apply ((wp whenE_throwError_wp check_vp_wpR ensure_empty_stronger|
              wpc|
              simp add: valid_arch_inv_def valid_aci_def is_aligned_shiftl_self)+)[1]
             apply (rule_tac Q'=
                         "\<lambda>rv. real_cte_at rv and 
                               ex_cte_cap_wp_to is_cnode_cap rv and 
                               (\<lambda>s. descendants_of (snd (excaps!0)) (cdt s) = {}) and
                               cte_wp_at (\<lambda>c. \<exists>idx. c = (cap.UntypedCap frame pageBits idx)) (snd (excaps!0)) and
                               (\<lambda>s. arm_asid_table (arch_state s) free = None)"
                         in hoare_post_imp_R)
              apply (simp add: lookup_target_slot_def)
              apply wp
             apply (clarsimp simp: cte_wp_at_def)
             apply (rule conjI, clarsimp)
             apply (rule shiftl_less_t2n)
              apply (rule order_less_le_trans, rule ucast_less, simp)
              apply (simp add: asid_bits_def asid_low_bits_def)
             apply (simp add: asid_bits_def)
            apply (simp split del: split_if) 
            apply (wp ensure_no_children_sp select_ext_weak_wp select_wp whenE_throwError_wp|wpc | simp add: K_bind_def)+
     apply clarsimp
     apply (rule conjI, fastforce)
     apply (cases excaps, simp)
     apply (case_tac list, simp)
     apply clarsimp
     apply (rule conjI)
      apply (drule cte_wp_at_norm, clarsimp, drule cte_wp_valid_cap, fastforce)+
      apply (clarsimp simp add: diminished_def)
     apply (rule conjI)
      apply clarsimp
      apply (simp add: ex_cte_cap_wp_to_def)
      apply (rule_tac x=ac in exI)
      apply (rule_tac x=ba in exI)
      apply (clarsimp simp add: cte_wp_at_caps_of_state)
      apply (drule (1) caps_of_state_valid[rotated])+
      apply (drule (1) diminished_is_update)+
      
      apply (clarsimp simp: is_cap_simps cap_rights_update_def)
     apply (clarsimp simp add: cte_wp_at_caps_of_state)
     apply (drule (1) caps_of_state_valid[rotated])+
     apply (drule (1) diminished_is_update)+
     apply (clarsimp simp: cap_rights_update_def)
    apply (clarsimp simp:diminished_def)
    apply (simp add: arch_decode_invocation_def Let_def split_def 
                cong: if_cong split del: split_if)
    apply (cases "invocation_type label = ARMPageMap")
     apply (rename_tac word rights vmpage_size option)
     apply (simp split del: split_if)
     apply (rule hoare_pre)
      apply ((wp whenE_throwError_wp check_vp_wpR hoare_vcg_const_imp_lift_R
                 create_mapping_entries_parent_for_refs find_pd_for_asid_pd_at_asid 
                 create_mapping_entries_valid_slots create_mapping_entries_same_refs_ex
             | wpc
             | simp add: valid_arch_inv_def valid_page_inv_def is_pg_cap_def
             | rule_tac x="fst p" in hoare_imp_eq_substR)+)[1]
         apply (rule hoare_vcg_conj_liftE_R)
          apply (simp add: find_pd_for_asid_def)
          apply ((wp_trace assertE_wp whenE_throwError_wp find_pd_for_asid_pd_at_asid | wpc)+)[1]
         apply (rule_tac Q'="\<lambda>rv s. page_directory_at rv s \<and>
                           args ! 0 < kernel_base \<and>
                           valid_arch_state s \<and>
                           valid_arch_objs s \<and>
                           equal_kernel_mappings s \<and>
                           pspace_aligned s \<and>
                           valid_global_objs s \<and>
                           (\<exists>\<rhd> rv) s \<and>
                           page_directory_at rv s \<and>
                           typ_at (AArch (AIntData vmpage_size)) word s \<and>
                           is_aligned (addrFromPPtr word) pageBits \<and>
                           args ! 0 < kernel_base \<and>
                           s \<turnstile> ArchObjectCap (PageCap word rights vmpage_size (Some (snd p, args ! 0))) \<and>
                           snd p \<le> mask asid_bits \<and>
                           snd p \<noteq> 0 \<and>
                           invs s \<and>
                           (\<exists>\<rhd> rv) s \<and>
                           page_directory_at rv s \<and>
                           is_aligned rv pd_bits \<and>
                           args ! 0 < kernel_base \<and> (pd_at_asid (snd p) rv s)" in hoare_post_imp_R)
          prefer 2
          apply auto[1]
         apply (wp assertE_wp whenE_throwError_wp find_pd_for_asid_pd_at_asid | wpc)+
     apply (clarsimp simp: neq_Nil_conv)
     apply (rule conjI)
      apply (clarsimp simp add: cte_wp_at_caps_of_state)
      apply (drule (1) caps_of_state_valid[rotated])+
      apply (drule (1) diminished_is_update)+
      apply (clarsimp simp: is_arch_update_def is_arch_cap_def)
      apply (simp add: cap_master_cap_def vs_cap_ref_def
                       cap_rights_update_def acap_rights_update_def 
                split:option.split vmpage_size.split)
     apply (rule conjI, fastforce dest!: cte_wp_at_page_cap_weaken)+
     apply (frule diminished_cte_wp_at_valid_cap[where p="(a, b)" for a b],
                  clarsimp+)
     apply (clarsimp simp: valid_cap_def
                           cap_aligned_def)
     apply (simp add: invs_def valid_state_def valid_pspace_def)
     apply (rule conjI)
      apply (clarsimp simp: cte_wp_at_caps_of_state dest!:diminished_pd_capD)
      apply (clarsimp simp: cte_wp_at_caps_of_state valid_arch_caps_def)
      apply (drule valid_vs_lookupD[OF vs_lookup_pages_apI])
         apply (simp add: obj_at_def)
        apply assumption+
      apply (clarsimp  simp: vs_cap_ref_def)
      apply (clarsimp split: cap.splits arch_cap.splits vmpage_size.splits 
                             option.splits)
      apply (drule valid_objs_caps)
      apply (frule_tac p="(a,ba)" in valid_capsD)
       apply assumption
      apply (clarsimp simp: valid_cap_def)
      apply (drule asid_low_high_bits[rotated])
         apply (simp add: mask_asid_low_bits_ucast_ucast)+
      apply (fastforce simp: diminished_pd_self)
     apply (simp add: vmsz_aligned_def split: vmpage_size.splits)
     apply (simp add: conj_comms)
     apply (rule conjI, simp, rule conjI, simp add: mask_def)
     apply (rule conjI)
      apply (rule is_aligned_addrFromPPtr)
      apply (erule is_aligned_weaken)
      apply (rule pbfs_atleast_pageBits)
     apply (simp add: linorder_not_le kernel_base_less_observation)
     apply (subst(asm) mask_lower_twice[symmetric])
      prefer 2
      apply (subst(asm) add_diff_eq[symmetric],
             subst(asm) is_aligned_add_helper,
             assumption)
       apply simp
      apply simp
     apply (case_tac vmpage_size, simp_all)[1]
    apply (cases "invocation_type label = ARMPageRemap")
     apply (rename_tac word rights vmpage_size option)
     apply (simp split del: split_if)
     apply (rule hoare_pre)
      apply ((wp whenE_throwError_wp check_vp_wpR hoare_vcg_const_imp_lift_R
                 create_mapping_entries_parent_for_refs 
            | wpc
            | simp add: valid_arch_inv_def valid_page_inv_def
            | (simp add: cte_wp_at_caps_of_state, 
                wp create_mapping_entries_same_refs_ex hoare_vcg_ex_lift_R))+)[1]
         apply (rule_tac Q'="\<lambda>rv s. fst p = rv \<and> fst pa = snd p \<longrightarrow>
                           pd_at_asid (fst pa) rv s \<and>
                           valid_arch_state s \<and>
                           valid_arch_objs s \<and>
                           equal_kernel_mappings s \<and>
                           pspace_aligned s \<and>
                           valid_global_objs s \<and>
                           (\<exists>\<rhd> fst p) s \<and>
                           page_directory_at (fst p) s \<and>
                           typ_at (AArch (AIntData vmpage_size)) word s \<and>
                           is_aligned (addrFromPPtr word) pageBits \<and>
                           vmsz_aligned (snd pa) vmpage_size \<and>
                           snd pa < kernel_base \<and>
                           snd p \<le> mask asid_bits \<and>
                           snd p \<noteq> 0 \<and>
                           invs s \<and>
                           (\<exists>\<rhd> fst p) s \<and>
                           page_directory_at (fst p) s \<and>
                           is_aligned (fst p) pd_bits \<and>
                           vmsz_aligned (snd pa) vmpage_size \<and>
                           snd pa < kernel_base \<and>
                           (\<exists>v va vb.
                               caps_of_state s (v, va) = Some vb \<and>
                               valid_arch_state s \<and>
                               valid_arch_objs s \<and>
                               valid_vs_lookup s \<and>
                               unique_table_refs (caps_of_state s) \<and>
                               pspace_aligned s \<and>
                               valid_objs s \<and>
                               valid_kernel_mappings s \<and>
                               (\<exists>\<rhd> fst p) s \<and>
                               (\<exists>pd_cap.
                                   (\<exists>a b. cte_wp_at (diminished pd_cap) (a, b) s) \<and>
                                   (\<exists>asid. pd_cap = ArchObjectCap (PageDirectoryCap (fst p) (Some asid)) \<and>
                                           page_directory_at (fst p) s \<and>
                                           snd pa < kernel_base \<and>
                                           (\<exists>rights'.
                                               vb =
                                               ArchObjectCap
                                                (PageCap word rights' vmpage_size
                                                  (Some (asid, snd pa)))))))" in hoare_post_imp_R)
          prefer 2
          apply clarsimp
          apply (rule conjI[rotated], auto)[1]
          apply (rule_tac x=v in exI, rule_tac x=va in exI)
          apply (rule_tac x="(ArchObjectCap (PageCap word rights' vmpage_size (Some (asid, ba))))" in exI)
          apply auto[1]   
         apply (rule mp [OF strengthen_validE_R_cong])
          apply (rule impI)
          apply (subst eq_commute[where b="snd p"])
          apply assumption
         apply (simp add: conj_comms)
         apply ((wp_trace whenE_throwError_wp check_vp_wpR hoare_vcg_const_imp_lift_R
                    hoare_drop_impE_R create_mapping_entries_parent_for_refs
               | wpc
               | simp add: valid_arch_inv_def valid_page_inv_def)+)[4]
         apply (simp add: find_pd_for_asid_def)
         apply (wp assertE_wp whenE_throwError_wp | wpc)+
     apply (clarsimp simp: valid_cap_def cap_aligned_def)
     apply (auto simp: vmsz_aligned_def invs_def valid_state_def mask_def
                       valid_arch_caps_def cte_wp_at_caps_of_state
                 elim: is_aligned_weaken 
               intro!: is_aligned_addrFromPPtr pbfs_atleast_pageBits)[1]
     apply (clarsimp simp: valid_pspace_def)
     apply (drule valid_vs_lookupD[OF vs_lookup_pages_apI])
        apply (simp add: obj_at_def)
       apply assumption+
     apply (clarsimp  simp: vs_cap_ref_def)
     apply (clarsimp split: cap.splits arch_cap.splits vmpage_size.splits 
                             option.splits)
     apply (drule valid_objs_caps)
     apply (frule_tac p="(aa,ba)" in valid_capsD)
      apply assumption
     apply (clarsimp simp: valid_cap_def)
     apply (drule asid_low_high_bits[rotated])
        apply (simp add: mask_asid_low_bits_ucast_ucast)+
     apply (rule exI[where x="fst slot"], rule exI[where x="snd slot"], 
            rule_tac x=cap in exI, rule conjI, simp)
     apply (rule_tac x="cap.ArchObjectCap (arch_cap.PageDirectoryCap xb (Some a))" in exI)
     apply (rule conjI)
      apply (fastforce simp: diminished_pd_self)
     apply (clarsimp simp: diminished_def mask_cap_def cap_rights_update_def 
                           acap_rights_update_def 
                    split: cap.splits arch_cap.splits)
    apply (cases "invocation_type label = ARMPageUnmap")
     apply (simp split del: split_if)
     apply (rule hoare_pre, wp)
     apply (clarsimp simp: valid_arch_inv_def valid_page_inv_def)
     apply (thin_tac "Ball S P" for S P)
     apply (rule conjI)
      apply (clarsimp split: option.split)
      apply (clarsimp simp: valid_cap_def cap_aligned_def)
      apply (simp add: valid_unmap_def)
      apply (fastforce simp: vmsz_aligned_def elim: is_aligned_weaken intro!: pbfs_atleast_pageBits)
     apply (erule cte_wp_at_weakenE)
     apply (clarsimp simp: is_arch_diminished_def is_cap_simps)
    apply (cases "isPageFlush (invocation_type label)")
     apply (simp split del: split_if)
     apply (rule hoare_pre)
      apply (wp whenE_throwError_wp static_imp_wp hoare_drop_imps)
        apply (simp add: valid_arch_inv_def valid_page_inv_def)
        apply (wp find_pd_for_asid_pd_at_asid | wpc)+
     apply (clarsimp simp: valid_cap_def mask_def)
    apply (simp split del: split_if)
    apply (cases "invocation_type label = ARMPageGetAddress")
     apply (simp split del: split_if)
     apply (rule hoare_pre, wp)
     apply (clarsimp simp: valid_arch_inv_def valid_page_inv_def)
    apply (rule hoare_pre, wp)
   apply (simp)
   apply (simp add: arch_decode_invocation_def Let_def split_def
                    is_final_cap_def
               cong: if_cong split del: split_if)
   apply (rename_tac word option)
   apply (rule hoare_pre)
    apply ((wp whenE_throwError_wp check_vp_wpR get_master_pde_wp hoare_vcg_all_lift_R|
            wpc|
            simp add: valid_arch_inv_def valid_pti_def unlessE_whenE vs_cap_ref_def|
            rule_tac x="fst p" in hoare_imp_eq_substR|
            wp_once hoare_vcg_ex_lift_R)+)[1]

         apply (rule_tac Q'="\<lambda>a b. ko_at (ArchObj (PageDirectory pd))
                                    (a + (args ! 0 >> 20 << 2) && ~~ mask pd_bits) b \<longrightarrow>
                                    pd (ucast (a + (args ! 0 >> 20 << 2) && mask pd_bits >> 2)) =
                                    InvalidPDE \<longrightarrow> L word option p pd a b" for L in hoare_post_imp_R[rotated])
          apply (intro impI)
          apply (erule impE)
           apply clarsimp
          apply (erule impE)
           apply (clarsimp split:ARM_Structs_A.pde.splits)
          apply assumption
         apply ((wp whenE_throwError_wp hoare_vcg_all_lift_R
                    find_pd_for_asid_lookup_slot [unfolded lookup_pd_slot_def Let_def]
                    find_pd_for_asid_ref_offset_voodoo find_pd_for_asid_shifting_voodoo
                    find_pd_for_asid_inv|
                 wpc|
                 simp add: valid_arch_inv_def valid_pti_def unlessE_whenE empty_pde_atI
                           vs_cap_ref_def|
                 wp_once hoare_drop_imps hoare_vcg_ex_lift_R)+)[6]
   apply (clarsimp simp: is_cap_simps)
   apply (rule conjI)
    apply clarsimp
    apply (rule conjI, fastforce)
    apply (rule conjI, fastforce)
    apply (clarsimp simp: neq_Nil_conv)
    apply (thin_tac "Ball S P" for S P)
    apply (rule conjI)
     apply (clarsimp simp: valid_cap_def cap_aligned_def)
    apply (rule conjI)
     apply (drule cte_wp_at_norm, clarsimp, drule cte_wp_valid_cap, fastforce)+
     apply (drule (1) diminished_is_update[rotated])+
     apply (clarsimp simp add: cap_rights_update_def acap_rights_update_def)
     apply (clarsimp simp: valid_cap_def cap_aligned_def
                           pt_bits_def pageBits_def
                           linorder_not_le
                           order_le_less_trans[OF word_and_le2])
     apply (rule is_aligned_andI2)
     apply (simp add: is_aligned_mask)
    apply (rule conjI)
     apply (clarsimp simp add: cte_wp_at_caps_of_state)
     apply (drule (1) caps_of_state_valid[rotated])
     apply (drule (1) diminished_is_update)
     apply clarsimp
     apply (clarsimp simp: cap_master_cap_def is_arch_update_def)
     apply (clarsimp simp: cap_asid_def cap_rights_update_def acap_rights_update_def is_cap_simps
                    split: option.split)
    apply (rule conjI, fastforce)
    apply (rule conjI, fastforce)
    apply (clarsimp simp: pde_ref_def)
    apply (frule invs_pd_caps)
    apply (clarsimp simp: cte_wp_at_caps_of_state)
    apply (frule (1) caps_of_state_valid[rotated])
    apply (drule (1) diminished_is_update)
    apply (clarsimp simp: cap_rights_update_def acap_rights_update_def valid_cap_def)
    apply (drule (2) valid_table_caps_ptD)
    apply (rule conjI, fastforce)+
    apply (clarsimp simp: kernel_vsrefs_def)
    apply (simp add: linorder_not_le, drule minus_one_helper3)
    apply (drule le_shiftr[where n=20], drule(1) order_trans)
    apply (simp add: kernel_base_def)
   apply (clarsimp simp: cte_wp_at_def is_arch_diminished_def is_cap_simps)
  apply (simp add: arch_decode_invocation_def Let_def  split del: split_if)
  apply (cases "isPDFlush (invocation_type label)")
   apply (simp split del: split_if)
   apply (rule hoare_pre)
    apply (wp whenE_throwError_wp static_imp_wp hoare_drop_imp | wpc | simp)+
          apply (simp add: resolve_vaddr_def)
          apply (wp get_master_pte_wp get_master_pde_wp whenE_throwError_wp | wpc | simp)+
        apply (clarsimp simp: valid_arch_inv_def valid_pdi_def)+
        apply (rule_tac Q'="\<lambda>pd' s. pd_at_asid x2 pd' s \<and> x2 \<le> mask asid_bits \<and> x2 \<noteq> 0" in hoare_post_imp_R)
         apply wp
        apply clarsimp
       apply (wp | wpc)+
   apply (clarsimp simp: valid_cap_def mask_def)
  apply (clarsimp, wp throwError_validE_R)
  done

declare word_less_sub_le [simp]

crunch st_tcb_at: perform_page_table_invocation, perform_page_invocation,
           perform_asid_pool_invocation, perform_page_directory_invocation "st_tcb_at P t"
  (wp: crunch_wps set_mrs_st_tcb simp: crunch_simps)

lemma delete_objects_st_tcb_at:
  "\<lbrace>st_tcb_at P t and invs and K (t \<notin> {ptr .. ptr + 2 ^ bits - 1})\<rbrace> 
    delete_objects ptr bits
  \<lbrace>\<lambda>y. st_tcb_at P t\<rbrace>"
  by (wp|simp add: delete_objects_def do_machine_op_def split_def)+


lemma arch_pinv_st_tcb_at:
  "\<lbrace>invs and valid_arch_inv ai and ct_active and 
    st_tcb_at (P and (Not \<circ> inactive) and (Not \<circ> idle)) t\<rbrace>
     arch_perform_invocation ai
   \<lbrace>\<lambda>rv. st_tcb_at P t\<rbrace>"
  apply (cases ai, simp_all add: arch_perform_invocation_def valid_arch_inv_def)
      apply (wp perform_page_table_invocation_st_tcb_at,
             fastforce elim!: st_tcb_weakenE)
     apply (wp perform_page_directory_invocation_st_tcb_at, fastforce elim: st_tcb_weakenE)
    apply (wp perform_page_invocation_st_tcb_at, fastforce elim!: st_tcb_weakenE)
   apply (wp perform_asid_control_invocation_st_tcb_at,
          fastforce elim!: st_tcb_weakenE)
  apply (wp perform_asid_pool_invocation_st_tcb_at,
         fastforce elim!: st_tcb_weakenE)
  done

lemma get_cap_diminished:
  "\<lbrace>valid_objs\<rbrace> get_cap slot \<lbrace>\<lambda>cap. cte_wp_at (diminished cap) slot\<rbrace>"
  apply (wp get_cap_wp)
  apply (intro allI impI)
  apply (simp add: cte_wp_at_caps_of_state diminished_def)
  apply (frule (1) caps_of_state_valid_cap)
  apply (clarsimp simp add: valid_cap_def2 wellformed_cap_def mask_cap_def
             cap_rights_update_def acap_rights_update_def
           split: cap.splits arch_cap.splits)
    apply fastforce+
  apply (clarsimp simp add: wellformed_acap_def
           split: cap.splits arch_cap.splits)
  apply (rename_tac rights vmpage_size option)
  apply (rule_tac x=rights in exI)
  apply auto
  done

end
